home *** CD-ROM | disk | FTP | other *** search
Text File | 1993-04-17 | 40.3 KB | 2,069 lines | [TEXT/KEEN] |
- #$hAWK_to_Cd2 : goal is to translate a hAWK program into C.
- ######## INCOMPLETE ############, and still very much under development
- #Run it on a copy of one of your hAWK programs if you're curious
- #to see what it does, but don't be too disappointed if the translation
- #to C is less than perfect. There is very little error checking at this
- #stage, and the run-time package that will actually execute the output
- #from this program (after it is compiled with THINK C) doesn't exist yet.
-
- #Although this program doesn't yet do anything useful, in it you'll
- #find a fairly complete lexer and parser for hAWK. The parser is of
- #the hand-coded recursive-descent type, and can be compared with
- #the YACC-style parser in AWKTAB.C/Y if you're interested in the inner
- #workings of hAWK.
-
- #Some issues are not yet resolved, and the final version of this
- #program may be rather different. At present, it's doing a decent job
- #and hasn't locked up in quite a while. Pass it one hAWK program as input,
- #and look for output in files with the same name but ending in '.c' and '.h'.
-
- # User’s Manual references:
- # «hAWK User’s Manual» «F Running hAWK programs»
- # «hAWK User’s Manual» «L 5 Regular expressions»
- # «hAWK User’s Manual» «M 5 Built-in string and file functions»
- # «hAWK User’s Manual» «K 4 Built-in variables»
- # «hAWK User’s Manual» «K 8 Arrays»
- # «hAWK User’s Manual» «N User-defined functions»
- # «hAWK User’s Manual» «P 3 The getline function»
- # «hAWK User’s Manual» «O 3 Output into files»
- # «hAWK User’s Manual» «Q The hAWK function»
-
-
- BEGIN { didNL = 1; # fudge for first time only
- num_constants = 0
- loosePrint = 0
- # Construct file names
- z = split(ARGV[1], names, ":")
- filename = names[z];
- sub(/^$/, "", filename)
- filename = substr(filename, 1, 29)
- outfileC = filename ".c"
- for (i = z-1; i >= 1; --i) #note i = z gives the input file name proper
- outfileC = names[i] ":" outfileC;#put path in front of outfile name
- len = length(outfileC) - 1
- outfileH = substr(outfileC, 1, len)
- outfileH = outfileH "h"
- outfileF = substr(outfileC, 1, len)
- outfileF = outfileF "f"
- outfileB = substr(outfileC, 1, len)
- outfileB = outfileB "b"
- outfileE = substr(outfileC, 1, len)
- outfileE = outfileE "z"
- outfile = outfileC
-
- init_toktypes() # for multi-char tokens
- init_tables() #builtin functions, keywords
-
- translate()
- filename = filename ".c"
- print_instructions()
- }
-
- function print_instructions()
- {
- print "Entering"" print_instructions"
- print "Output is in"
- print outfileC
- print "and"
- print outfileH
- print ""
- print "Install", filename, "as the bottom-most file in"
- print "the THINK C project \"hAWK_to_C.π\", then \"Update\""
- print "and \"Build Code Resource\" to the folder \"Chawk programs\"."
- print ""
- print "To run your new compiled program, start up your favourite"
- print "Drag_on Module - compatible editor, select \"Chawk\" from"
- print "a menu, and then pick your new program from the \"Program\""
- print "popup menu in the resulting dialog."
- }
-
- #advance(), the lexical analyzer;
- # Removes white space, but notices newlines
- # Puts next token in tok, removes it from current input line
- # At end of file, returns "(eof)"
- # Note toktype is set to a special UPPERCASE token type only for
- # names, numbers, or other things longer than one char; else
- # being only a single char, toktype is set to the char.
- # This includes "~" and "=" and "*" for example, but excludes
- # single-letter names, and also numbers.
- #NOTE CONCAT_OP is inferred by two exps jammed together, space
- #in between is not required, eg "hello""there"
- function advance( temp, in_bracket, c,r)
- {
- print "Entering"" advance"
- print "Previous token:", tok
- print "Line:", line
- if (toktype == EOF) return
- if (nextTok != "") #use lookahead
- {
- tok = nextTok
- toktype = nextTokType
- nextTok = ""
- return
- }
- sub(/^[ \t]+/, "", line) #remove leading white
- if (match(line, /^#/)) #kill if comment
- {
- line = substr(line,2)
- gen("/*" line "*/")
- line = ""
- }
- while (length(line) == 0)
- {
- if (!didNL)
- {
- didNL = 1
- toktype = NEWLINE
- tok = "\n"
- return
- }
- else
- didNL = 0;
- if (getline line == 0)
- {
- toktype = EOF
- tok = "(eof)"
- return
- }
- # line continuation
- while (match(line, /\\$/))
- {
- getline temp
- line = substr(line, 1, length(line)-1) temp
- }
- #immediately remove comments and leading white
- sub(/^[ \t]+/, "", line) #remove leading white
- if (match(line, /^#/)) #kill if comment
- {
- line = substr(line,2)
- gen("/*" line "*/")
- line = ""
- }
- }
- if (want_regexp) #just saw "/" when wanted
- {
- #wrinkles: watch for \/ and / inside []
- #TO DO line continuation and newline - see AWK.Y
- toktype = REGEXP
- while ((c = substr(line,1,1)) != "")
- {
- if (!in_bracket && c == "/")
- {
- line = substr(line, 2) #skip closing /
- tok = r
- return
- }
- if (c == "\\")
- {
- r = r c
- line = substr(line, 2)
- c = substr(line,1,1)
- }
- else if (c == "[")
- in_bracket = 1
- else if (c == "]")
- in_bracket = 0
- r = r c
- line = substr(line, 2)
- }
- error("Couldn't find end of regular expression")
- }
- if (match(line, /^[A-Za-z_](\w|_)*/)) #identifier
- {
- tok = substr(line, 1, RLENGTH)
- line = substr(line, RLENGTH+1)
- if (tok == "print")
- toktype = LEX_PRINT
- else if (tok == "printf")
- toktype = LEX_PRINTF
- else if (tok == "getline")
- toktype = LEX_GETLINE
- else if (tok in hAWK_BUILTIN)
- toktype = LEX_BUILTIN
- else if (tok in hAWK_LENGTH)
- toktype = LEX_LENGTH
- else if (tok in hAWK_KEY)
- toktype = KEY
- #Wrinkle; is it immediately followed by a "("?
- else if (substr(line, 1, 1) == "(")
- toktype = FUNC_CALL
- else
- toktype = NAME
- return
- }
- if (match(line, /^([0-9]+\.?[0-9]*|\.[0-9]+)([eE][+-]?[0-9]+)?/)) #number
- toktype = NUMBER
- ##else if (match(line, /^".*([^\\]?|(\\\\)+)"/)) #string
- else if (match(line, /^"[^"]*"/)) #string
- {
- toktype = YSTRING
- if (index(line, "\\"))
- {
- painfully_match_string()
- return
- }
- }
- else if (match(line, /^>>/)) #redir append
- toktype = APPEND_OP
- else if (match(line, /^(<=|==|!=|>=)/)) #relational
- toktype = RELOP
- else if (match(line, /^\+\+/))
- toktype = INCREMENT
- else if (match(line, /^--/))
- toktype = DECREMENT
- else if (match(line, /^(\+=|-=|\*=|\/=|\^=|%=)/))#assign, inc
- toktype = ASSIGNOP
- else if (match(line, /^&&/))
- toktype = LEX_AND
- else if (match(line, /^\|\|/))
- toktype = LEX_OR
- else if (match(line, /^!~/))
- toktype = MATCHOP
- else if (match(line, /^./)) #everything else
- {
- #TO DO trap illegal tokens, eg "@"
- toktype = substr(line,1,1)
- }
- else
- error("Unexpected empty line")
- tok = substr(line, 1, RLENGTH)
- line = substr(line, RLENGTH+1)
- }
-
- function painfully_match_string( c, esc, i, len)
- {
- esc = 0
- len = length(line)
- for (i = 2; i <= len; ++i)
- {
- c = substr(line,i,1)
- if (c == "\"")
- {
- if (esc == 0 || esc%2 == 0)
- break;
- else
- esc = 0
- }
- else if (c == "\\")
- ++esc
- else
- esc = 0
- }
- if (i > len)
- error("string has no end in line ")
- tok = substr(line, 1, i)
- line = substr(line, i+1)
- }
-
- #Single lookahead, preserving current tok and toktype,
- #sets nextTok to token, and nextTokType to type.
- function lex_next( oldTok, oldTokType)
- {
- print "Entering"" lex_next"
- if (nextTok != "")
- return
- oldTok = tok
- oldTokType = toktype
- advance()
- nextTok = tok
- nextTokType = toktype
- tok = oldTok
- toktype = oldTokType
- }
-
- #print s with nt leading tabs
- # Four possible destinations:
- # -outfileC, all patterns/actions
- # -outfileF, all function definitions
- # -outfileB/E, BEGIN, END
- # Note code for global defs and prototypes is stored
- # in array before printing to outfileH. At end, the
- # T/B/E files are appended to outfileC, and outfileH
- # is included always at top of outfileC
- function gen(s)
- {
- print "Entering"" gen"
- printf("%s%s\n", substr("\t\t\t\t\t\t\t\t\t", 1, nt), s) > outfile
- }
-
- #not used
- function gen_no_slashn(s)
- {
- print "Entering"" gen_no_slashn"
- printf("%s%s", substr("\t\t\t\t\t\t\t\t\t", 1, nt), s) > outfile
- }
-
-
- #read next token if s == tok
- function eat(s)
- {
- print "Entering"" eat"
- if (tok != s) error("expected " s)
- advance()
- }
-
- #absorb optional newlines
- function newline()
- {
- print "Entering"" newline"
- while (tok == "\n")
- advance()
- }
-
- function error(s)
- {
- print "Error:", s
- print "Location:", names[z], NR
- print "Current Line:", line
- print "Current token", tok
- print "Current toktype:", toktype
- exit 1
- }
-
- ############ the parser proper ###############
-
- function translate()
- {
- print "Entering"" translate"
- advance() # done first to emit any top comments
- newline() #also to get opening comments
- ##while (toktype != EOF)
- ## {
- ## print tok, toktype
- ## advance()
- ## }
- ##return
-
- gen("")
- boiler_plate() #open up the output files
- nt = 2
- start()
- gen("END_GETREC:") #for "next" jumps
- gen("}") # end of while getrec
- --nt
- gen("END();")
- gen("}") #end of function "program"
- outfile = outfileB
- gen("}")
- outfile = outfileE
- gen("}")
- close(outfileF)
- close(outfileB)
- close(outfileE)
- #emit BEGIN, END, user function definitions, globals
- emit_functions() # to outfileC
- emit_globalsEtc() #to outfileH
- }
-
- function boiler_plate()
- {
- print "Entering"" boiler_plate"
- #Note this comes after any opening comments in original
- gen("/* " filename ".c */")
- gen("#include \"" filename ".h\"")
- gen("")
- gen("RETTYPE program()\n\t{");
- gen("\tinit_consts_and_vars();")
- gen("\tBEGIN();")
- gen("\twhile (getrec())\n\t\t{")
-
- outfile = outfileB
- gen("RETTYPE BEGIN()\n\t{")
-
- outfile = outfileE
- gen("RETTYPE END()\n\t{")
-
- outfile = outfileC
- }
-
- #start
- # : {NEWLINE} rule {NEWLINE} {rule {NEWLINE}}
- # ;
- function start()
- {
- print "Entering"" start"
- #advance() - done before, to emit opening comments before boiler plate
- newline()
- rule()
- newline()
- while (toktype != EOF)
- {
- rule()
- newline()
- }
- }
-
- #rule
- # : LEX_BEGIN action
- # | LEX_END action
- # | pattern action
- # | action
- # | pattern statement_term
- # | function_prologue function_body
- # ;
- function rule()
- {
- print "Entering"" rule"
- if (toktype == KEY && tok == "BEGIN")
- {
- outfile = outfileB
- oldNT = nt
- nt = 1
- advance()
- action()
- outfile = outfileC
- nt = oldNT
- }
- else if (toktype == KEY && tok == "END")
- {
- outfile = outfileE
- oldNT = nt
- nt = 1
- advance()
- action()
- outfile = outfileC
- nt = oldNT
- }
- else if (toktype == KEY && (tok == "function" || tok == "func"))
- {
- outfile = outfileF
- oldNT = nt
- nt = 0
- function_prologue()
- function_body()
- empty_not_globals()
- outfile = outfileC
- nt = oldNT
- }
- else if (tok == "{")
- {
- action()
- }
- else if (toktype != EOF)
- {
- gen("if (" pattern() ")")
- nt++
- gen("{")
- if (tok == "{")
- {
- action()
- }
- else #default is print $0
- {
- statement_term()
- gen("print(field((AWKNUM)0));")
- }
- gen("}")
- nt--
- }
- }
-
- #func_name
- # : NAME
- # | FUNC_CALL
- # ;
- function func_name( name)
- {
- print "Entering"" func_name"
- if (toktype == NAME || toktype == FUNC_CALL)
- {
- name = tok "_u"
- advance()
- return name
- }
- else
- error("Expected but did not find a function name")
- }
-
- #function_prologue
- # : LEX_FUNCTION func_name "(" [param_list] ")" {NEWLINE}
- # ;
- function function_prologue( name)
- {
- print "Entering"" function_prologue"
- if (tok == "func")
- eat("func")
- else
- eat("function")
- name = func_name()
- eat("(")
- gen("RETTYPE " name "(" param_list() ")")
- eat(")")
- newline()
- }
-
- #function_body
- # : "{" {NEWLINE} statements "}" {NEWLINE}
- # ;
- function function_body()
- {
- print "Entering"" function_body"
- ++nt
- eat("{")
- gen("{")
- newline()
- statements()
- eat("}")
- gen("return( return_it(copy_to_temp(NULLNODE)) );") #just in case....
- gen("}\n")
- newline()
- }
-
- #pattern
- # : exp0 ["," {NEWLINE} exp0]
- # ;
- # from_to(int, val1, val2) returns "Bool", internally tracks
- #whether range has been activated - note returns "TRUE" for val2
- #and then deactivates. "ranger" is an index, use tbd
- function pattern( e)
- {
- print "Entering"" pattern"
- e = exp0()
- if (tok ==",") #range pattern, latch on/switch off
- {
- advance()
- newline()
- return "from_to(" ranger++ ", " e ", " exp0() ")"
- }
- else
- return e
- }
-
- #regexp
- # * In this rule, want_regexp tells yylex that the next thing
- # * is a regexp so it should read up to the closing slash.
- # : "/" REGEXP "/"
- # ;
- # Note toktype is REGEXP, slashes not included
- function regexp( r)
- {
- print "Entering"" regexp"
- if (tok == "/")
- {
- want_regexp = 1
- advance()
- want_regexp = 0
- r = "SLSHREG, " "\"" tok "\""
- advance()
- if (r in const)
- return "CONSTANT_NODE(" const[r] ")"
- else
- {
- const[r] = num_constants
- return "CONSTANT_NODE(" num_constants++ ")"
- }
- }
- else
- error("regular expression not terminated with \"/\"")
- }
-
- #action
- # : "{" {NEWLINE} "}" {NEWLINE} [";"]
- # <
- # * empty actions are different from missing actions *
- # $$ = node ((NODE *) NULL, Node_illegal, (NODE *) NULL);
- # >
- # | "{" {NEWLINE} statements "}" {NEWLINE} [";"]
- # ;
- function action()
- {
- print "Entering"" action"
- eat("{")
- newline()
- if (tok == "}") #empty action
- {
- advance()
- newline()
- if (tok == ";")
- advance()
- gen("null_op();")
- }
- statements()
- eat("}")
- newline()
- if (tok == ";")
- advance()
- }
-
- #statements
- # : statement {statement}
- # ;
- function statements( rsult)
- {
- print "Entering"" statements"
- statement()
- while (first_of_statement())
- statement()
- }
-
- #statement_term
- # : NEWLINE {NEWLINE}
- # | ";" {NEWLINE}
- # ???| implied by "}"
- # ;
- #Note statement_term is not optional when called for.
- function statement_term()
- {
- print "Entering"" statement_term"
- if (tok == ";")
- {
- advance()
- newline()
- }
- else if (tok == "\n")
- newline()
- else if (tok == "}")
- return
- else
- error("statement not terminated")
- }
-
- #statement
- # : ";" {NEWLINE}
- # | "{" {NEWLINE} "}" {NEWLINE}
- # | "{" {NEWLINE} statements "}" {NEWLINE}
- # | if_statement
- # | LEX_WHILE "(" exp0 ")" {NEWLINE} statement
- # | LEX_DO {NEWLINE} statement LEX_WHILE "(" exp0 ")" {NEWLINE}
- # | LEX_FOR "(" NAME LEX_IN NAME ")" {NEWLINE} statement
- # | LEX_FOR "(" [exp0] ";" [exp0] ";" [exp0] ")" {NEWLINE} statement
- # | LEX_BREAK statement_term
- # | LEX_CONTINUE statement_term
- # | print "(" expression_list ")" output_redir statement_term
- # | print opt_rexpression_list output_redir statement_term
- # | LEX_NEXT statement_term
- # | LEX_EXIT [exp0] statement_term
- # | LEX_RETURN [exp0] statement_term
- # | LEX_DELETE NAME "[" expression_list "]" statement_term
- # | exp0 statement_term
- # ;
- #This is the main code generating function
- #Note: output_redir() returns "to_stdout()" if there isn't one
- function statement( e,f,g, add_curly)
- {
- print "Entering"" statement"
- if (tok == ";")
- {
- gen("CLEARTEMPSTACK();")
- advance()
- newline()
- }
- else if (tok == "{")
- {
- gen("{")
- advance()
- newline()
- while (first_of_statement())
- statement()
- #TO DO -special emit if block was empty?
- eat("}")
- gen("}")
- newline()
- }
- else if (tok == "if")
- {
- if_statement()
- }
- else if (tok == "while")
- {
- advance()
- eat("(")
- gen("while (" exp0() ")")
- eat(")")
- ++nt
- newline()
- if (tok != "{")
- {
- add_curly = 1
- gen("{")
- }
- statement()
- if (add_curly == 1)
- gen("}")
- --nt
- }
- else if (tok == "do")
- {
- advance()
- newline()
- gen("do")
- ++nt
- if (tok != "{")
- {
- add_curly = 1
- gen("{")
- }
- statement()
- if (add_curly == 1)
- gen("}")
- ++nt
- eat("while")
- eat("(")
- gen("while (" exp0() ");")
- eat(")")
- newline()
- --nt
- --nt
- }
- else if (tok == "for")
- {
- advance()
- eat("(")
- if (toktype == NAME)
- {
- lex_next()
- if (nextTok == "in")
- {
- #for (assign(NAME1, first_in(NAME2); *string_val(NAME1);
- # assign(NAME1, next_in(NAME2))
- e = tok #first name
- if (!(e in hAWK_VAR))
- e = e "_u"
- record_if_global(e)
- advance() # to the "in"
- eat("in") #now tok = second name
- if (!(tok in hAWK_VAR))
- tok = tok "_u"
- record_if_global(tok)
- gen("for (assign(" e ", first_in(" tok "); *string_val( " e ");")
- gen("\t\tassign(" e ", next_in(" tok "))")
- advance() # ")"
- eat(")")
- ++nt
- newline()
- if (tok != "{")
- {
- add_curly = 1
- gen("{")
- }
- statement()
- if (add_curly == 1)
- gen("}")
- --nt
- }
- else #plain for, starting with NAME
- {
- e = exp0()
- eat(";")
- if (tok != ";")
- f = exp0()
- eat(";")
- if (tok != ")")
- g = exp0()
- eat(")")
- gen("for(" e ";" f ";" g ")")
- ++nt
- newline()
- if (tok != "{")
- {
- add_curly = 1
- gen("{")
- }
- statement()
- if (add_curly == 1)
- gen("}")
- --nt
- }
- }
- else #plain for
- {
- if (tok != ";")
- e = exp0()
- eat(";")
- if (tok != ";")
- f = exp0()
- eat(";")
- if (tok != ")")
- g = exp0()
- eat(")")
- gen("for(" e ";" f ";" g ")")
- ++nt
- newline()
- if (tok != "{")
- {
- add_curly = 1
- gen("{")
- }
- statement()
- if (add_curly == 1)
- gen("}")
- --nt
- }
- }
- else if (tok == "break")
- {
- gen("CLEARTEMPSTACK();")
- advance()
- gen("break;")
- statement_term()
- }
- else if (tok == "continue")
- {
- gen("CLEARTEMPSTACK();")
- advance()
- gen("continue;")
- statement_term()
- }
- else if (tok == "print")
- {
- gen("CLEARTEMPSTACK();")
- advance()
- if (tok == "(")
- {
- advance()
- e = expression_list()
- eat(")")
- f = output_redir()
- statement_term()
- gen("do_print(" f ", " num_expressions ", " e ");")
- }
- else
- {
- e = opt_rexpression_list()
- f = output_redir()
- statement_term()
- gen("do_print(" f ", " num_expressions ", " e ");")
- }
- }
- else if (tok == "printf")
- {
- gen("CLEARTEMPSTACK();")
- advance()
- if (tok == "(")
- {
- advance()
- e = expression_list()
- eat(")")
- f = output_redir()
- statement_term()
- gen("do_printf(" f ", " num_expressions ", " e ");")
- }
- else
- {
- e = opt_rexpression_list()
- f = output_redir()
- statement_term()
- gen("do_printf(" f ", " num_expressions ", " e ");")
- }
- }
- else if (tok == "next")
- {
- gen("CLEARTEMPSTACK();")
- advance()
- statement_term()
- gen("do_next();")
- }
- else if (tok == "exit")
- {
- gen("CLEARTEMPSTACK();")
- advance()
- if (tok != "\n" && tok != ";")
- exp0()
- statement_term()
- gen("do_exit();")
- }
- else if (tok == "return")
- {
- gen("CLEARTEMPSTACK();")
- advance()
- if (tok != "\n" && tok != ";")
- {
- e = exp0()
- statement_term()
- gen("return(return_it(" e "));")
- }
- else
- {
- statement_term()
- gen("return( return_it(copy_to_temp(NULLNODE)) );")
- }
- }
- else if (tok == "delete")
- {
- gen("CLEARTEMPSTACK();")
- advance()
- e = tok
- if (toktype != NAME)
- error("delete not followed by array name")
- if (!(e in hAWK_VAR))
- e = e "_u"
- record_if_global(e)
- advance()
- eat("[")
- f = expression_list()
- eat("]")
- statement_term()
- gen("array_delete(" e ", array_index(" num_expressions ", " f "));")
- }
-
- else
- {
- gen("CLEARTEMPSTACK();")
- gen(exp0() ";")
- statement_term()
- }
- }
-
- #if_statement
- # : LEX_IF "(" exp0 ")" {NEWLINE} statement [ LEX_ELSE {NEWLINE} statement ]
- # ;
- function if_statement( add_curly)
- {
- print "Entering"" if_statement"
- advance()
- eat("(")
- gen("if (" exp0() ")")
- eat(")")
- ++nt
- newline()
- if (tok != "{")
- {
- add_curly = 1
- gen("{")
- }
- statement()
- if (add_curly == 1)
- gen("}")
- --nt
- if (tok == "else")
- {
- advance()
- gen("else")
- newline()
- if (tok != "if")
- {
- ++nt
- if (tok != "{")
- {
- add_curly = 1
- gen("{")
- }
- statement()
- if (add_curly == 1)
- gen("}")
- --nt
- }
- else
- statement()
- }
- }
-
- #input_redir
- # : * empty *
- # | "<" simp_exp
- # ;
- function input_redir()
- {
- print "Entering"" input_redir"
- if (tok != "<")
- return "from_stdin()"
- else
- {
- advance()
- return "from_file(" simp_exp() ")"
- }
- }
-
- #output_redir
- # : { (">" | ">>") exp0 }
- # ;
- function output_redir()
- {
- print "Entering"" output_redir"
- if (toktype == ">" || toktype == APPEND_OP)
- {
- advance()
- if (toktype == ">")
- return "redirect(" exp0() ")"
- else
- return "redirect_append(" exp0() ")"
- }
- else
- return "to_stdout()"
- }
-
- #param_list
- # : NAME { "," {NEWLINE} NAME }
- # ;
- # Note at this stage just the raw list of names, without
- # even commas, is created. When function is copied from
- # outfileF to outfileC then the proper declarations and commas
- # are issued.
- function param_list( parms)
- {
- print "Entering"" param_list"
- if (tok == ")")
- return ""
- if (toktype != NAME)
- error("Name is missing from function parameters")
- if (!(tok in hAWK_VAR))
- tok = tok "_u"
- parms = tok
- record_not_global(tok)
- advance()
- if (tok == ")")
- return parms
- else
- {
- eat(",")
- newline()
- }
- while (tok != ")")
- {
- if (toktype != NAME)
- error("Name is missing from function parameters")
- if (!(tok in hAWK_VAR))
- tok = tok "_u"
- parms = parms " " tok
- record_not_global(tok)
- advance()
- if (tok == ",")
- {
- eat(",")
- newline()
- }
- }
- return parms
- }
-
- # LA is tok != ">"|">>"|"<"|";"|"\n"
- #opt_rexpression_list
- # : <loosePrint = 1>
- # [ exp0 { "," {NEWLINE} exp0 } ]
- # <loosePrint = 0>
- # ;
- #Called only for print, so returns $0 if list is empty
- function opt_rexpression_list( e)
- {
- print "Entering"" opt_rexpression_list"
- num_expressions = 1
- if (!(toktype in follow_opt_r_list))
- {
- loosePrint = 1
- e = exp0()
- while (tok == ",")
- {
- eat(",")
- newline()
- e = e ", " exp0()
- ++num_expressions
- }
- loosePrint = 0
- }
- else
- e = "field((AWKNUM)0)"
- return e
- }
-
- # LA is tok != ")" only
- #opt_expression_list
- # : [ expression_list ]
- # ;
- function opt_expression_list()
- {
- print "Entering"" opt_expression_list"
- if (tok != ")")
- return expression_list()
- else
- {
- num_expressions = 0
- return ""
- }
- }
-
- #expression_list
- # : exp0 { "," {NEWLINE} exp0 }
- # ;
- function expression_list( e)
- {
- print "Entering"" expression_list"
- e = exp0()
- num_expressions = 1
- while (tok == ",")
- {
- advance()
- newline()
- e = e ", " exp0()
- ++num_expressions
- }
- return e
- }
-
- #exp0 : variable ASSIGNOP exp0
- # | exp1
- # ;
- function exp0( e,f)
- {
- print "Entering"" exp0"
- e = exp1()
- if (toktype == ASSIGNOP || toktype == "=")
- {
- #Technically should check that e can be assigned to.
- f = tok
- advance()
- return op_table[f] e ", " exp0() ")"
- }
- else
- return e
- }
-
- #exp1 : exp2 {"?" exp2 ":" exp2 }
- function exp1( e)
- {
- print "Entering"" exp1"
- e = exp2()
- if (tok == "?")
- {
- advance()
- return "T_F(" e ") ? " exp1()
- }
- else if (tok == ":")
- {
- advance()
- return e ":" exp1()
- }
- else
- return e
- }
-
- #exp2 : exp3 { "||" exp3 }
- # ;
- function exp2( e)
- {
- print "Entering"" exp2"
- e = exp3()
- if (toktype == LEX_OR)###
- e = "T_F(" e ")"###
- while (toktype == LEX_OR)
- {
- advance()
- e = e " || T_F(" exp3() ")"###
- ##e = "op_or(" exp3() ", " e ")"
- }
- return e
- }
-
- #exp3 : exp4 { "&&" exp4 }
- # ;
- function exp3( e)
- {
- print "Entering"" exp3"
- e = exp4()
- if (toktype == LEX_AND)###
- e = "T_F(" e ")"###
- while (toktype == LEX_AND)
- {
- advance()
- e = e " && T_F(" exp4() ")"###
- ##e = "op_and(" exp4() ", " e ")"
- }
- return e
- }
-
- #exp4 : exp5 [LEX_IN NAME]
- # ;
- #first for input_redir is "<" or zip - note it returns
- # from_stdin() if no redirect.
- #first for var is NAME or "$" (note it's optional)
- function exp4( e,f)
- {
- print "Entering"" exp4"
- e = exp5()
- if (tok == "in")
- {
- advance()
- if (toktype != NAME)
- error("No array name following \"in\" operator")
- f = tok
- if (!(f in hAWK_VAR))
- f = f "_u"
- record_if_global(f)
- advance()
- return "in(" e ", " f ")"
- }
- return e
- }
-
- #exp5 : exp6 { MATCHOP exp6 }
- # ;
- function exp5( e, f)
- {
- print "Entering"" exp5"
- e = exp6()
- while (toktype == MATCHOP || tok == "~")
- {
- f = tok
- advance()
- e = op_table[f] exp6() ", " e ")"
- }
- return e
- }
-
- # do ">"|"<" only if !loosePrint
- #exp6 : exp7 { (RELOP|">"|"<") exp7 }
- # ;
- function exp6( e, f)
- {
- print "Entering"" exp6"
- e = exp7()
- while (toktype == RELOP || toktype == "<" ||
- (!loosePrint && (toktype == ">")))
- {
- f = tok
- advance()
- e = op_table[f] exp7() ", " e ")"
- }
- return e
- }
-
- #exp7 : exp8 { exp8 } - implied CONCAT_OP
- # ;
- function exp7( e)
- {
- print "Entering"" exp7"
- e = exp8();
- while (!(toktype in follow_exp8))
- e = "concat(" exp8() ", " e ")"
- return e
- }
-
- #exp8 : exp9 { ("+"|"-") exp9 }
- # ;
- function exp8( e,f)
- {
- print "Entering"" exp8"
- e = exp9()
- while (tok == "+" || tok == "-")
- {
- f = tok
- advance()
- e = op_table[f] exp9() ", " e ")"
- }
- return e
- }
-
- #exp9 : exp10 { ("*"|"/"|"%") exp10 }
- # ;
- function exp9( e, f)
- {
- print "Entering"" exp9"
- e = exp10()
- while (tok == "*" || tok == "/" || tok == "%")
- {
- f = tok
- advance()
- e = op_table[f] exp10() ", " e ")"
- }
- return e
- }
-
- #exp10 : "!" ( regexp | exp11 )
- # | [("+"|"-")] exp11
- # ;
- function exp10( re)
- {
- print "Entering"" exp10"
- if (tok == "!")
- {
- eat("!")
- if (tok == "/")
- {
- re = "string_to_regex(" regexp() ")"
- }
- else
- re = exp11()
- return "op_not(" re ")"
- }
- else
- {
- if (tok == "+" || tok == "-")
- {
- if (tok == "-")
- {
- advance()
- return "op_negate(" exp11() ")"
- }
- else
- {
- advance()
- return exp11()
- }
- }
- else
- return exp11()
- }
- }
-
- #exp11 : exp12 { "^" exp12 }
- # ;
- #Note exponentiation is right-associative, the recursive call
- #to exp11 is not a typo.
- function exp11( e)
- {
- print "Entering"" exp11"
- e = exp12()
- if (tok == "^")
- {
- advance()
- return "op_exp(" e ", " exp11() ")"
- }
- else
- return e
- }
-
- #exp12 : YSTRING | NUMBER
- # | regexp
- # |GETLINE [variable] [input_redir]
- # | LEX_BUILTIN "(" opt_expression_list ")"
- # | LEX_LENGTH "(" opt_expression_list ")"
- # | LEX_LENGTH
- # | FUNC_CALL "(" opt_expression_list ")"
- # | [("++"|"--")] variable
- # | variable ("++"|"--")
- # | "(" exp0 ( ")" |
- # "," {NEWLINE} exp0
- # { "," {NEWLINE} exp0 }
- # ")" LEX_IN NAME )
- # ;
- function exp12( e,f)
- {
- print "Entering"" exp12"
- if (tok == "/")
- {
- return regexp()
- }
- else if (toktype == YSTRING)
- {
- e = "STRING, " tok
- advance()
- if (e in const)
- return "CONSTANT_NODE(" const[e] ")"
- else
- {
- const[e] = num_constants
- return "CONSTANT_NODE(" num_constants++ ")"
- }
- }
- else if (toktype == NUMBER)
- {
- e = "DOUBLE, \"" tok "\"" #for init_consts_and_vars()
- advance()
- if (e in const)
- return "CONSTANT_NODE(" const[e] ")"
- else
- {
- const[e] = num_constants
- return "CONSTANT_NODE(" num_constants++ ")"
- }
- }
- else if (toktype == LEX_GETLINE)
- {
- advance()
- if (toktype == NAME || tok == "$")
- e = variable()
- else
- e = "NULL"
- return "get_line(" e ", " input_redir() ")"
- }
- else if (toktype == LEX_BUILTIN)
- {
- f = hAWK_BUILTIN[tok]
- advance()
- eat("(")
- e = opt_expression_list()
- eat(")")
- return f"(" e ")"
- }
- else if (toktype == LEX_LENGTH)
- {
- f = hAWK_LENGTH[tok]
- advance()
- if (tok != "(")
- return f "(field((AWKNUM)0))"
- else
- {
- eat("(")
- e = opt_expression_list()
- eat(")")
- return f"(" e ")"
- }
- }
- else if (toktype == FUNC_CALL)
- {
- f = tok "_u"
- advance()
- eat("(")
- e = opt_expression_list()
- #max number of args in a function call determines split
- #between parameters and local variables
- if (num_expressions > maxparms[f]+0)
- maxparms[f] = num_expressions
- eat(")")
- return f "(" e ")"
- }
- else if (tok == "(")
- {
- advance()
- e = exp0()
- if (tok == ")")
- {
- advance()
- if (tok != "in")
- return e
- else
- {
- advance()
- if (toktype != NAME)
- error("No array name following \"in\" operator")
- f = tok
- if (!(f in hAWK_VAR))
- f = f "_u"
- record_if_global(f)
- advance()
- return "in(array_index(1, " e "), " f ")"
- }
- }
- else
- {
- num_expressions = 1
- while (tok != ")")
- {
- eat(",")
- newline()
- e = e "," exp0()
- ++num_expressions
- }
- advance()
- eat("in")
- if (toktype != NAME)
- error("No array name following \"in\" operator")
- f = tok
- if (!(f in hAWK_VAR))
- f = f "_u"
- record_if_global(f)
- advance()
- return "in(array_index(num_expressions, " e "), " f ")"
- }
- }
- else if (tok == "++" || tok == "--")
- {
- f = tok
- advance()
- if (f == "++")
- return "op_preinc(" variable() ")"
- else
- return "op_predec(" variable() ")"
- }
- else #gotta be a variable
- {
- e = variable()
- if (tok == "++" || tok == "--")
- {
- f = tok
- advance()
- if (f == "++")
- return "op_postinc(" e ")"
- else
- return "op_postdec(" e ")"
- }
- else
- return e
- }
- }
-
- #simp_exp: sexp9 { ("+"|"-") sexp9 }
- # ;
- function simp_exp( e,f)
- {
- print "Entering"" simp_exp"
- e = sexp9()
- while (tok == "+" || tok == "-")
- {
- f = tok
- advance()
- e = op_table[f] sexp9() ", " e ")"
- }
- return e
- }
-
- #sexp9 : sexp10 { ("*"|"/"|"%") sexp10 }
- # ;
- function sexp9( e,f)
- {
- print "Entering"" sexp9"
- e = sexp10()
- while (tok == "*" || tok == "/" || tok == "%")
- {
- f = tok
- advance()
- e = op_table[f] sexp10() ", " e ")"
- }
- return e
- }
-
- #sexp10 : ["!"|"+"|"-"] sexp11
- # ;
- function sexp10()
- {
- print "Entering"" sexp10"
- if (tok == "!")
- {
- eat("!")
- return "op_not(" sexp11() ")"
- }
- else
- {
- if (tok == "+" || tok == "-")
- {
- if (tok == "-")
- {
- advance()
- return "op_negate(" sexp11() ")"
- }
- else
- {
- advance()
- return sexp11()
- }
- }
- else
- return sexp11()
- }
- }
-
- #sexp11 : sexp12 { "^" sexp12 }
- # ;
- #Note exponentiation is right-associative, the recursive call
- #to sexp11 is not a typo.
- function sexp11( e)
- {
- print "Entering"" sexp11"
- e = sexp12()
- if (tok == "^")
- {
- advance()
- return "op_exp(" e ", " sexp11() ")"
- }
- else
- return e
- }
-
- #sexp12 : YSTRING | NUMBER
- # | LEX_BUILTIN "(" opt_expression_list ")"
- # | LEX_LENGTH "(" opt_expression_list ")"
- # | LEX_LENGTH
- # | FUNC_CALL "(" opt_expression_list ")"
- # | [("++"|"--")] variable
- # | variable ("++"|"--")
- # | "(" exp0 ")"
- # ;
- function sexp12( e,f)
- {
- print "Entering"" sexp12"
- if (toktype == YSTRING)
- {
- e = "STRING, " tok
- advance()
- if (e in const)
- return "CONSTANT_NODE(" const[e] ")"
- else
- {
- const[e] = num_constants
- return "CONSTANT_NODE(" num_constants++ ")"
- }
- }
- else if (toktype == NUMBER)
- {
- e = "DOUBLE, \"" tok "\"" #for init_consts_and_vars()
- advance()
- if (e in const)
- return "CONSTANT_NODE(" const[e] ")"
- else
- {
- const[e] = num_constants
- return "CONSTANT_NODE(" num_constants++ ")"
- }
- }
- else if (toktype == LEX_BUILTIN)
- {
- f = hAWK_BUILTIN[tok]
- advance()
- eat("(")
- e = opt_expression_list()
- eat(")")
- return f"(" e ")"
- }
- else if (toktype == LEX_LENGTH)
- {
- f = hAWK_LENGTH[tok]
- advance()
- if (tok != "(")
- return f "(field((AWKNUM)0))"
- else
- {
- eat("(")
- e = opt_expression_list()
- eat(")")
- return f"(" e ")"
- }
- }
- else if (toktype == FUNC_CALL)
- {
- f = tok "_u"
- advance()
- eat("(")
- e = opt_expression_list()
- #max number of args in a function call determines split
- #between parameters and local variables
- if (num_expressions > maxparms[f]+0)
- maxparms[f] = num_expressions
- eat(")")
- return f "(" e ")"
- }
- else if (tok == "(")
- {
- advance()
- e = exp0()
- eat(")")
- return e
- }
- else if (tok == "++" || tok == "--")
- {
- f = tok
- advance()
- if (f == "++")
- return "op_preinc(" variable() ")"
- else
- return "op_predec(" variable() ")"
- }
- else #gotta be a variable
- {
- e = variable()
- if (tok == "++" || tok == "--")
- {
- f = tok
- advance()
- if (f == "++")
- return "op_postinc(" e ")"
- else
- return "op_postdec(" e ")"
- }
- else
- return e
- }
- }
-
- #variable
- # : NAME
- # | NAME "[" expression_list "]"
- # | "$" simp_exp
- # ;
- function variable( id, se)
- {
- print "Entering"" variable"
- if (toktype == NAME)
- {
- if (!(tok in hAWK_VAR))
- tok = tok "_u"
- record_if_global(tok)
- id = tok
- advance()
- if (tok == "[")
- {
- advance()
- se = expression_list()
- eat("]")
- return "array(" id ", array_index(" num_expressions ", " se "))"
- return "array(" id ", " se ")"
- }
- else
- return id
- }
- else if (tok == "$")
- {
- advance()
- return "field(" simp_exp() ")"
- }
- else
- error("expected variable or constant")
- }
-
- # 37 ways to name your token
- function init_toktypes()
- {
- print "Entering"" init_toktypes"
- FUNC_CALL = 258
- NAME = 259
- REGEXP = 260
- ERROR = 261
- NUMBER = 262
- YSTRING = 263
- RELOP = 264
- APPEND_OP = 265
- ASSIGNOP = 266
- MATCHOP = 267
- NEWLINE = 268
- CONCAT_OP = 269
- LEX_BEGIN = 270
- LEX_END = 271
- LEX_IF = 272
- LEX_ELSE = 273
- LEX_RETURN = 274
- LEX_DELETE = 275
- LEX_WHILE = 276
- LEX_DO = 277
- LEX_FOR = 278
- LEX_BREAK = 279
- LEX_CONTINUE = 280
- LEX_PRINT = 281
- LEX_PRINTF = 282
- LEX_NEXT = 283
- LEX_EXIT = 284
- LEX_FUNCTION = 285
- LEX_GETLINE = 286
- LEX_IN = 287
- LEX_AND = 288
- LEX_OR = 289
- INCREMENT = 290
- DECREMENT = 291
- LEX_BUILTIN = 292
- LEX_LENGTH = 293
- UNARY = 294
- KEY = 295
- EOF = 296
- }
-
- # hAWK_BUILTIN, hAWK_LENGTH, hAWK_KEY arrays (tables)
- function init_tables()
- {
- print "Entering"" init_tables"
- hAWK_BUILTIN["atan2"] = "fn_atan2"
- hAWK_BUILTIN["close"] = "fn_close"
- hAWK_BUILTIN["cos"] = "fn_cos"
- hAWK_BUILTIN["exp"] = "fn_exp"
- hAWK_BUILTIN["gsub"] = "fn_gsub"
- hAWK_BUILTIN["hAWK"] = "fn_hAWK"
- hAWK_BUILTIN["index"] = "fn_index"
- hAWK_BUILTIN["int"] = "fn_int"
- hAWK_BUILTIN["log"] = "fn_log"
- hAWK_BUILTIN["match"] = "fn_match"
- hAWK_BUILTIN["progress"] = "fn_progress"
- hAWK_BUILTIN["prompt"] = "fn_prompt"
- hAWK_BUILTIN["rand"] = "fn_rand"
- hAWK_BUILTIN["sin"] = "fn_sin"
- hAWK_BUILTIN["sort"] = "fn_sort"
- hAWK_BUILTIN["split"] = "fn_split"
- hAWK_BUILTIN["sprintf"] = "fn_sprintf"
- hAWK_BUILTIN["sqrt"] = "fn_sqrt"
- hAWK_BUILTIN["srand"] = "fn_srand"
- hAWK_BUILTIN["sub"] = "fn_sub"
- hAWK_BUILTIN["substr"] = "fn_substr"
- hAWK_BUILTIN["system"] = "fn_system"
- hAWK_BUILTIN["time"] = "fn_time"
- hAWK_BUILTIN["tolower"] = "fn_tolower"
- hAWK_BUILTIN["toupper"] = "fn_toupper"
-
- hAWK_LENGTH["length"] = "fn_length"
- hAWK_LENGTH["lookup"] = "fn_lookup"
-
- hAWK_KEY["BEGIN"] = 1
- hAWK_KEY["END"] = 1
- hAWK_KEY["break"] = 1
- hAWK_KEY["continue"] = 1
- hAWK_KEY["delete"] = 1
- hAWK_KEY["do"] = 1
- hAWK_KEY["else"] = 1
- hAWK_KEY["exit"] = 1
- hAWK_KEY["for"] = 1
- hAWK_KEY["func"] = 1
- hAWK_KEY["function"] = 1
- hAWK_KEY["getline"] = 1
- hAWK_KEY["if"] = 1
- hAWK_KEY["in"] = 1
- hAWK_KEY["next"] = 1
- hAWK_KEY["print"] = 1
- hAWK_KEY["printf"] = 1
- hAWK_KEY["return"] = 1
- hAWK_KEY["while"] = 1
-
- # builtin variables
- hAWK_VAR["ARGC"] = 1
- hAWK_VAR["ARGV"] = 1
- hAWK_VAR["FILENAME"] = 1
- hAWK_VAR["FNR"] = 1
- hAWK_VAR["FS"] = 1
- hAWK_VAR["IGNORECASE"] = 1
- hAWK_VAR["NF"] = 1
- hAWK_VAR["NR"] = 1
- hAWK_VAR["OFMT"] = 1
- hAWK_VAR["OFS"] = 1
- hAWK_VAR["ORS"] = 1
- hAWK_VAR["RS"] = 1
- hAWK_VAR["RSTART"] = 1
- hAWK_VAR["RLENGTH"] = 1
- hAWK_VAR["SUBSEP"] = 1
- hAWK_VAR["RUNERR"] = 1
- hAWK_VAR["STDPATH"] = 1
- hAWK_VAR["TIME"] = 1
-
- #table of function names, implementing operators
- #Not in the table; || && getline in funccall redirection
- # unary +/- ++ -- $ ()
- op_table["="] = "op_assign("
- op_table["+="] = "op_plus_equals("
- op_table["-="] = "op_minus_equals("
- op_table["*="] = "op_times_equals("
- op_table["/="] = "op_div_equals("
- op_table["%="] = "op_mod_equals("
- op_table["^="] = "op_exp_equals("
- op_table["~"] = "op_match("
- op_table["!~"] = "op_not_match("
- op_table["<"] = "op_lt("
- op_table["<="] = "op_le("
- op_table[">"] = "op_gt("
- op_table[">="] = "op_ge("
- op_table["=="] = "op_equiv("
- op_table["!="] = "op_not_equiv("
- op_table["+"] = "op_plus("
- op_table["-"] = "op_minus("
- op_table["*"] = "op_times("
- op_table["/"] = "op_div("
- op_table["%"] = "op_mod("
- op_table["!"] = "op_not("
- op_table["^"] = "op_exp("
-
- #first and follow sets
- #follow_exp8 is used to tell if concatenation is needed
- follow_exp8["="] = 1
- follow_exp8[ASSIGNOP] = 1
- follow_exp8["?"] = 1
- follow_exp8[":"] = 1
- follow_exp8[LEX_OR] = 1
- follow_exp8[LEX_AND] = 1
- follow_exp8[KEY] = 1
- follow_exp8[EOF] = 1
- follow_exp8[MATCHOP] = 1
- follow_exp8[RELOP] = 1
- follow_exp8["~"] = 1
- follow_exp8["<"] = 1
- follow_exp8[">"] = 1
- follow_exp8[","] = 1
- follow_exp8[";"] = 1
- follow_exp8["}"] = 1
- follow_exp8["{"] = 1
- follow_exp8[")"] = 1
- follow_exp8["]"] = 1
- follow_exp8[NEWLINE] = 1
-
- follow_opt_r_list[">"] = 1
- follow_opt_r_list[APPEND_OP] = 1
- follow_opt_r_list["<"] = 1
- follow_opt_r_list[";"] = 1
- follow_opt_r_list[NEWLINE] = 1
-
- first_statement[";"] = 1
- first_statement["{"] = 1
- first_statement["("] = 1
- first_statement[KEY] = 1 #NOTE except BEGIN, END, else, in, func(tion)
- first_statement[LEX_PRINT] = 1
- first_statement[LEX_PRINTF] = 1
- first_statement["/"] = 1
- first_statement[NAME] = 1
- first_statement["$"] = 1
- first_statement[LEX_BUILTIN] = 1
- first_statement[LEX_LENGTH] = 1
- first_statement[FUNC_CALL] = 1
- first_statement[YSTRING] = 1
- first_statement[NUMBER] = 1
- first_statement["!"] = 1
- first_statement["+"] = 1
- first_statement["-"] = 1
- first_statement[INCREMENT] = 1
- first_statement[DECREMENT] = 1
-
- bad_first_stat_key["BEGIN"] = 1
- bad_first_stat_key["END"] = 1
- bad_first_stat_key["else"] = 1
- bad_first_stat_key["in"] = 1
- bad_first_stat_key["func"] = 1
- bad_first_stat_key["function"] = 1
- }
-
- function first_of_statement()
- {
- print "Entering"" first_of_statement"
- if (toktype in first_statement)
- {
- if (toktype != KEY)
- return 1
- if (tok in bad_first_stat_key)
- return 0
- return 1
- }
- else
- return 0
- }
-
- function record_not_global(n)
- {
- print "Entering"" record_not_global"
- not_global[n] = 1
- }
- function empty_not_globals( i)
- {
- print "Entering"" empty_not_globals"
- for (i in not_global)
- delete not_global[i]
- }
-
- function record_if_global(n)
- {
- print "Entering"" record_if_global"
- if (!(n in not_global) &&
- !(n in hAWK_VAR) &&
- !(n in globals))
- globals[n] = 1
- }
-
- ############## ##############
- #Create init_consts_and_vars to outfileC
- #Copy outfileB (BEGIN) and outfileE (END) to outfileC verbatim.
- #Copy outfileF to end of outfileC - includes
- #definitions for all user functions. Adjust declarations
- #and prototypes to move local decls inside function body.
- #Note in outfileF the parms are just a raw space-separated list
- #with no type or commas, good format for split()
- function emit_functions( i,n,m,p,loc,t,q,k)
- {
- print "Entering"" emit_functions"
- print "void init_consts_and_vars()\n\t{" > outfileC
- for (i in const)
- print "\tinit_constant_node(" const[i] ", " i ");" > outfileC
- gMax = sort(globals, gIndex, "d")
- if (gMax > 0)
- {
- print "/* globals */" > outfileC
- for (i = 1; i <= gMax; ++i)
- print "\tinit_var(" gIndex[i] ", NULLNODE);" > outfileC
- }
- print "\t}\n" > outfileC
- while (getline < outfileB > 0)
- print $0 > outfileC
- print "" > outfileC
- while (getline < outfileE > 0)
- print $0 > outfileC
- print "" > outfileC
- while (getline < outfileF > 0)
- {
- if ($0 ~ /^RETTYPE/) #start of function
- {
- #RETTYPE thefunc()
- #RETTYPE thefunc(x)
- #RETTYPE thefunc(x y z)
-
- match($0, /\(/)
- k = RSTART
- printf("%s", substr($0,1,RSTART)) > outfileC
- q = $2
- if (match(q, /\(/))
- {
- q = substr(q,1,RSTART-1)
- sub(/[ \t]+/, "", q)
- }
- protos[q] = "RETTYPE " q "("
- m = maxparms[q]+0
- $0 = substr($0,k+1)
- sub(/\)/, "")
- n = split($0, p)
- if (n > 0)
- {
- #output parms
- if (m > 0)
- {
- printf("VARTYPE %s_c", p[1]) > outfileC
- protos[q] = protos[q] "VARTYPE " p[1] "_c"
- }
- else
- protos[q] = protos[q] "void"
- for (i = 2; i <= m; ++i)
- {
- printf(", %s_c", p[i]) > outfileC
- protos[q] = protos[q] ", " p[i] "_c"
- }
- protos[q] = protos[q] ");"
- getline t < outfileF #skip over "{"
- printf(")\n\t{\n") > outfileC
-
- #output decls for copies of params, and locals
- if (m > 0)
- {
- printf("\tVARTYPE\t%s", p[1]) > outfileC
- for (i = 2; i <= m; ++i)
- printf(", %s", p[i]) > outfileC
- printf(";\n") > outfileC
- }
- if (m < n)
- {
- printf("\tVARTYPE\t%s", p[m+1]) > outfileC
- for (i = m+2; i <= n; ++i)
- printf(", %s", p[i]) > outfileC
- printf(";\n\n") > outfileC
- }
- else
- printf(";\n") > outfileC
- printf("\tentering_function();\n") > outfileC
- #init param copies, and null the locals
- for (i = 1; i <= m; ++i)
- printf("\t%s = init_local(%s_c);\n", p[i],p[i]) > outfileC
- for (i = m+1; i <= n; ++i)
- printf("\t%s = init_local(LOCALNULL);\n", p[i]) > outfileC
- }
- else
- {
- protos[q] = protos[q] "void);"
- printf(")\n") > outfileC
- }
- }
- else
- print $0 > outfileC
- }
- }
-
- # Output goes to outfileH
- function emit_globalsEtc( i)
- {
- print "Entering"" emit_globalsEtc"
- #title
- print "/* " filename ".h */" > outfileH
- #globals - NOTE they were just sorted in emit_functions above
- #gMax = sort(globals, gIndex, "d")
- if (gMax > 0)
- {
- print "/* Global variable definitions */" > outfileH
- printf("VARTYPE\t%s", gIndex[1]) > outfileH
- for (i = 2; i <= gMax; ++i)
- {
- if (i == 5*int(i/5))
- printf("\n") > outfileH
- printf(", %s", gIndex[i]) > outfileH
- }
- print ";" > outfileH
- print "" > outfileH
- }
- #prototypes
- #first, program init_consts_and_vars BEGIN END
- print "/* Standard function prototypes */" > outfileH
- print "RETTYPE program(void);" > outfileH
- print "void init_consts_and_vars(void);" > outfileH
- print "RETTYPE BEGIN(void);" > outfileH
- print "RETTYPE END(void);" > outfileH
- gMax = sort(protos, gIndex, "d")
- if (gMax > 0)
- {
- print "/* User function prototypes */" > outfileH
- for (i = 1; i <= gMax; ++i)
- print protos[gIndex[i]] > outfileH
- }
- }
-
-